home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / dvips.new / dospecial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-01-15  |  19.1 KB  |  720 lines

  1. /*
  2.  *   This routine handles special commands;
  3.  *   predospecial() is for the prescan, dospecial() for the real thing.
  4.  */
  5. #include "structures.h" /* The copyright notice in that file is included too! */
  6.  
  7. #include <ctype.h>
  8. extern int atoi();
  9.  
  10. /*
  11.  *   These are the external routines called:
  12.  */
  13. /**/
  14. #ifdef TPIC
  15. /*
  16.  * Fri Mar  9 1990  jourdan@minos.inria.fr (MJ)
  17.  * Upgraded to accommodate tpic release 2.0 extended output language.
  18.  * Should prove upward compatible!
  19.  */
  20. extern void setPenSize();
  21. extern void flushPath();
  22. extern void flushDashed();
  23. extern void flushDashed();
  24. extern void addPath();
  25. extern void arc();
  26. extern void flushSpline();
  27. extern void shadeLast();
  28. extern void whitenLast();
  29. extern void blackenLast();
  30. extern void SetShade() ;
  31. #endif
  32. extern shalfword dvibyte() ;
  33. extern int add_header() ;
  34. extern void hvpos() ;
  35. extern void figcopyfile() ;
  36. extern char *malloc() ;
  37. extern void nlcmdout() ;
  38. extern void cmdout() ;
  39. extern void numout() ;
  40. extern void scout() ;
  41. extern void stringend() ;
  42. extern void error() ;
  43. extern void psflush() ;
  44. extern char errbuf[] ;
  45. extern shalfword linepos;
  46. extern Boolean usesspecial ;
  47. extern int landscape ;
  48. extern char *paperfmt ;
  49. extern char *nextstring;
  50. extern char *maxstring;
  51. extern char *oname;
  52. extern FILE *bitfile;
  53. extern int quiet;
  54. extern fontdesctype *curfnt ;
  55. extern int actualdpi ;
  56. extern int vactualdpi ;
  57. extern integer hh, vv;
  58. extern int lastfont ;
  59. extern real conv ;
  60. extern real vconv ;
  61.  
  62. #ifdef DEBUG
  63. extern integer debug_flag;
  64. #endif
  65. extern void scanfontcomments() ;
  66.  
  67. struct bangspecial {
  68.    struct bangspecial *next ;
  69.    char actualstuff[1] ; /* more space will actually be allocated */
  70. } *bangspecials = NULL ;
  71.  
  72. #ifdef EMTEX
  73. /* subset of emtex specials */
  74.  
  75. #define EMMAX 1613 /* maximum number of emtex special points */
  76. #define TRUE 1
  77. #define FALSE 0
  78.  
  79. struct empt {
  80.    shalfword point;
  81.    integer x, y;
  82. };
  83.  
  84. struct empt *empoints = NULL;
  85. boolean emused = FALSE;  /* true if em points used on this page */
  86. integer emx, emy;
  87.  
  88. struct emunit {
  89.    char *unit;
  90.    float factor;
  91. };
  92. struct emunit emtable[] = {
  93.   {"pt",72.27},
  94.   {"pc",72.27/12},
  95.   {"in",1.0},
  96.   {"bp",72.0},
  97.   {"cm",2.54},
  98.   {"mm",25.4},
  99.   {"dd",72.27/(1238/1157)},
  100.   {"cc",72.27/12/(1238/1157)},
  101.   {"sp",72.27*65536},
  102.   {"",0.0}
  103. };
  104.  
  105.  
  106. /* clear the empoints array if necessary */
  107. void
  108. emclear()
  109. {
  110. int i;
  111.    if (emused && empoints)
  112.       for (i=0; i<EMMAX; i++)
  113.          empoints[i].point = 0;
  114.    emused = FALSE ;
  115. }
  116.  
  117. /* put an empoint into the empoints array */
  118. struct empt *emptput(point, x, y)
  119. shalfword point;
  120. integer x, y;
  121. {
  122. int i, start;
  123.  
  124.    emused = TRUE;
  125.    start = point % EMMAX;
  126.    i = start;
  127.    while ( empoints[i].point != 0 ) {
  128.       if ( empoints[i].point == point )
  129.          break;
  130.       i++;
  131.       if (i >= EMMAX)
  132.          i = 0;
  133.       if (i == start) {
  134.      sprintf(errbuf,"!Too many em: special points");
  135.      error(errbuf);
  136.       }
  137.    }
  138.  
  139.    empoints[i].point = point;
  140.    empoints[i].x = x;
  141.    empoints[i].y = y;
  142.    return(&empoints[i]);
  143. }
  144.  
  145. /* get an empoint from the empoints array */
  146. struct empt *emptget(point)
  147. shalfword point;
  148. {
  149. int i, start;
  150.  
  151.    start = point % EMMAX;
  152.    i = start;
  153.    if (emused == TRUE)
  154.       while ( empoints[i].point != 0 ) {
  155.          if (empoints[i].point == point)
  156.             return(&empoints[i]);
  157.          i++;
  158.          if (i >= EMMAX)
  159.             i = 0;
  160.          if (i == start)
  161.             break;
  162.       }
  163.    sprintf(errbuf,"!em: point %d not defined",point);
  164.    error(errbuf);
  165.    return(NULL); /* never returns due to error */
  166. }
  167.  
  168.  
  169. /* convert width into dpi units */
  170. float emunits(width,unit)
  171. float width;
  172. char *unit;
  173. {
  174. struct emunit *p;
  175.     for (p=emtable; *(p->unit)!='\0'; p++) {
  176.        if (strcmp(p->unit,unit)==0)
  177.         return( width * actualdpi / p->factor );
  178.     }
  179.     return (-1.0); /* invalid unit */
  180. }
  181. #endif /* EMTEX */
  182.  
  183.  
  184. static void trytobreakout(p)
  185. register char *p ;
  186. {
  187.    register int i ;
  188.    register int instring = 0 ;
  189.    int lastc = 0 ;
  190.  
  191.    i = 0 ;
  192.    while (*p) {
  193.       if (i > 65 && *p == ' ' && instring == 0) {
  194.          (void)putc('\n', bitfile) ;
  195.          i = 0 ;
  196.       } else {
  197.          (void)putc(*p, bitfile) ;
  198.          i++ ;
  199.       }
  200.       if (*p == '(' && lastc != '\\')
  201.          instring = 1 ;
  202.       else if (*p == ')' && lastc != '\\')
  203.          instring = 0 ;
  204.       lastc = *p ;
  205.       p++ ;
  206.    }
  207. }
  208.  
  209. static void dobs(q)
  210. register struct bangspecial *q ;
  211. {
  212.    if (q) {
  213.       dobs(q->next) ;
  214.       trytobreakout(q->actualstuff) ;
  215.    }
  216. }
  217.  
  218. void
  219. outbangspecials() {
  220.    if (bangspecials) {
  221.       cmdout("TeXDict") ;
  222.       cmdout("begin") ;
  223.       cmdout("@defspecial\n") ;
  224.       dobs(bangspecials) ;
  225.       cmdout("\n@fedspecial") ;
  226.       cmdout("end") ;
  227.    }
  228. }
  229.  
  230. /* We recommend that new specials be handled by the following general
  231.  * (and extensible) scheme, in which the user specifies one or more
  232.  * `key=value' pairs separated by spaces.
  233.  * The known keys are given in KeyTab; they take values
  234.  * of one of the following types:
  235.  *
  236.  * None: no value, just a keyword (in which case the = sign is omitted)
  237.  * String: the value should be "<string without double-quotes"
  238.  *                          or '<string without single-quotes'
  239.  * Integer: the value should be a decimal integer (%d format)
  240.  * Number: the value should be a decimal integer or real (%f format)
  241.  * Dimension: like Number, but will be multiplied by the scaledsize
  242.  *       of the current font and converted to default PostScript units
  243.  * (Actually, strings are allowed in all cases; the delimiting quotes
  244.  *  are simply stripped off if present.)
  245.  *
  246.  */
  247.  
  248. typedef enum {None, String, Integer, Number, Dimension} ValTyp;
  249. typedef struct {
  250.    char    *Entry;
  251.    ValTyp  Type;
  252. } KeyDesc;
  253.  
  254. #define NKEYS    (sizeof(KeyTab)/sizeof(KeyTab[0]))
  255.  
  256. KeyDesc KeyTab[] = {{"psfile",  String}, /* j==0 in the routine below */
  257.                     {"ifffile", String}, /* j==1 */
  258.                     {"tekfile", String}, /* j==2 */
  259.                     {"hsize",   Number},
  260.                     {"vsize",   Number},
  261.                     {"hoffset", Number},
  262.                     {"voffset", Number},
  263.                     {"hscale",  Number},
  264.                     {"vscale",  Number},
  265.                     {"angle",   Number},
  266.                     {"llx", Number},
  267.                     {"lly", Number},
  268.                     {"urx", Number},
  269.                     {"ury", Number},
  270.                     {"rwi", Number}};
  271.  
  272. #ifdef VMS
  273. #define Tolower _tolower
  274. #else
  275. /*
  276.  * compare strings, ignore case
  277.  */
  278. char Tolower(c)
  279. register char c ;
  280. {
  281.    if ('A' <= c && c <= 'Z')
  282.       return(c+32) ;
  283.    else
  284.       return(c) ;
  285. }
  286. #endif
  287. int IsSame(a, b)
  288. char *a, *b;
  289. {
  290.    for( ; *a != '\0'; )
  291.       if( Tolower(*a++) != Tolower(*b++) ) 
  292.          return( 0 );
  293.       return( *b == '\0' );
  294. }
  295.  
  296. char *KeyStr, *ValStr ; /* Key and String values found */
  297. long ValInt ; /* Integer value found */
  298. float ValNum ; /* Number or Dimension value found */
  299.  
  300. char  *GetKeyVal(str,tno) /* returns NULL if none found, else next scan point */
  301.    char *str ; /* starting point for scan */
  302.    int  *tno ; /* table entry number of keyword, or -1 if keyword not found */
  303. {
  304.    register char *s ;
  305.    register int i ;
  306.    register char t ;
  307.  
  308.    for (s=str; *s <= ' ' && *s; s++) ; /* skip over blanks */
  309.    if (*s == '\0')
  310.       return (NULL) ;
  311.    KeyStr = s ;
  312.    while (*s>' ' && *s!='=') s++ ;
  313.    if (t = *s)
  314.       *s++ = 0 ;
  315.  
  316.    for(i=0; i<NKEYS; i++)
  317.       if( IsSame(KeyStr, KeyTab[i].Entry) )
  318.          goto found ;
  319.    *tno = -1;
  320.    return (s) ;
  321.  
  322. found: *tno = i ;
  323.    if (KeyTab[i].Type == None)
  324.       return (s) ;
  325.  
  326.    if (t && t <= ' ') {
  327.       for (; *s <= ' ' && *s; s++) ; /* now look for the value part */
  328.       if ((t = *s)=='=')
  329.          s++ ;
  330.    }
  331.    ValStr = "" ;
  332.    if ( t == '=' ) {
  333.       while (*s <= ' ' && *s)
  334.          s++ ;
  335.       if (*s=='\'' || *s=='\"')
  336.          t = *s++ ;               /* get string delimiter */
  337.       else t = ' ' ;
  338.       ValStr = s ;
  339.       while (*s!=t && *s)
  340.          s++ ;
  341.       if (*s)
  342.          *s++ = 0 ;
  343.    }
  344.    switch (KeyTab[i].Type) {
  345.  case Integer:
  346.       if(sscanf(ValStr,"%ld",&ValInt)!=1) {
  347.           sprintf(errbuf,"Non-integer value (%s) given for keyword %s",
  348.               ValStr, KeyStr) ;
  349.           error(errbuf) ;
  350.           ValInt = 0 ;
  351.       }
  352.       break ;
  353.  case Number:
  354.  case Dimension:
  355.       if(sscanf(ValStr,"%f",&ValNum)!=1) {  
  356.           sprintf(errbuf,"Non-numeric value (%s) given for keyword %s",
  357.               ValStr, KeyStr) ;
  358.           error(errbuf) ;
  359.           ValNum = 0.0 ;
  360.       }
  361.       if (KeyTab[i].Type==Dimension) {
  362.          if (curfnt==NULL)
  363.             error("! No font selected") ;
  364.          ValNum = ValNum * ((double)curfnt->scaledsize) * conv * 72 / DPI ;
  365.       }
  366.       break ;
  367.  default: break ;
  368.    }
  369.    return (s) ;
  370. }
  371.  
  372. /*
  373.  *   Now our routines.  We get the number of bytes specified and place them
  374.  *   into the string buffer, and then parse it. Numerous conventions are
  375.  *   supported here for historical reasons.
  376.  */
  377.  
  378. void predospecial(numbytes, scanning)
  379. integer numbytes ;
  380. Boolean scanning ;
  381. {
  382.    register char *p = nextstring ;
  383.    register int i = 0 ;
  384.    int j ;
  385.  
  386.    if (nextstring + numbytes > maxstring)
  387.       error("! out of string space in predospecial") ;
  388.    for (i=numbytes; i>0; i--)
  389.       *p++ = (char)dvibyte() ;
  390.    while (p[-1] <= ' ' && p > nextstring)
  391.       p-- ; /* trim trailing blanks */
  392.    if (p==nextstring) return ; /* all blank is no-op */
  393.    *p = 0 ;
  394.    p = nextstring ;
  395.    while (*p <= ' ')
  396.       p++ ;
  397. #ifdef DEBUG
  398.    if (dd(D_SPECIAL))
  399.       (void)fprintf(stderr, "Preprocessing special: %s\n", p) ;
  400. #endif
  401.  
  402. /*
  403.  *   We use strncmp() here to also pass things like landscape()
  404.  *   or landscape: or such.
  405.  */
  406.  
  407.    if (strncmp(p, "landscape", 9)==0) {
  408.       landscape = 1 ;
  409.       return ;
  410.    }
  411.    if (strncmp(p, "xtex:", 5)==0) return ;
  412.    usesspecial = 1 ;  /* now the special prolog will be sent */
  413.    if (strncmp(p, "header", 6)==0) {
  414.       char *q ;
  415.       p += 6 ;
  416.       while ((*p <= ' ' || *p == '=' || *p == '(') && *p != 0)
  417.          p++ ;
  418.       q = p ;  /* we will remove enclosing parentheses */
  419.       p = p + strlen(p) - 1 ;
  420.       while ((*p <= ' ' || *p == ')') && p >= q)
  421.          p-- ;
  422.       p[1] = 0 ;
  423.       if (p >= q)
  424.          (void)add_header(q) ;
  425.    }
  426.    else if (*p == '!') {
  427.       register struct bangspecial *q ;
  428.       p++ ;
  429.       q = (struct bangspecial *)malloc((unsigned)
  430.                          (sizeof(struct bangspecial) + strlen(p))) ;
  431.       if (q == NULL)
  432.          error("! out of memory in predospecial") ;
  433.       (void)strcpy(q->actualstuff, p) ;
  434.       q->next = bangspecials ;
  435.       bangspecials = q ;
  436.    } else if (scanning && *p != '"' &&
  437.           (p=GetKeyVal(p, &j)) != NULL && j==0)
  438.       scanfontcomments(ValStr) ;
  439. }
  440.  
  441. void dospecial(numbytes)
  442. integer numbytes ;
  443. {
  444.    register char *p = nextstring ;
  445.    register int i = 0 ;
  446.    int j, systemtype = 0 ;
  447.    char psfile[100] ; 
  448.    char cmdbuf[100] ; 
  449.    register char *q ;
  450.    Boolean psfilewanted = 1 ;
  451.    extern int access() ;
  452. #ifdef EMTEX
  453. /* specials for emtex */
  454. float emwidth;
  455. shalfword empoint1, empoint2;
  456. struct empt *empoint;
  457. char emunit[3];
  458. char emstr[80];
  459. char *emp;
  460. #endif /* EMTEX */
  461.  
  462.    if (nextstring + i > maxstring)
  463.       error("! out of string space in dospecial") ;
  464.    for (i=numbytes; i>0; i--)
  465.       *p++ = (char)dvibyte() ;
  466.    while (p[-1] <= ' ' && p > nextstring)
  467.       p-- ; /* trim trailing blanks */
  468.    if (p==nextstring) return ; /* all blank is no-op */
  469.    *p = 0 ;
  470.    p = nextstring ;
  471.    while (*p <= ' ')
  472.       p++ ;
  473. #ifdef DEBUG
  474.    if (dd(D_SPECIAL))
  475.       (void)fprintf(stderr, "Processing special: %s\n", p) ;
  476. #endif
  477.  
  478. #ifdef EMTEX
  479. /* specials for emtex, added by rjl */
  480. /* at present,
  481.  * the line cut parameter is not supported (and is ignored)
  482.  * em:graph is not supported
  483.  */ 
  484.    if (strncmp(p, "em:", 3)==0) {
  485.         hvpos() ;
  486.     for (emp = p+3; *emp && isspace(*emp); emp++); /* skip blanks */
  487.     if (strncmp(emp, "linewidth", 9) == 0) {
  488.        /* code for linewidth */
  489.        for (emp = emp+9; *emp && isspace(*emp); emp++); /* skip blanks */
  490.        sscanf(emp, "%f%2s", &emwidth, emunit);
  491.        emwidth = emunits(emwidth,emunit);
  492.        if (emwidth!=-1.0) {
  493.           sprintf(emstr,"%.1f setlinewidth", emwidth);
  494.           cmdout(emstr);
  495. #ifdef DEBUG
  496.    if (dd(D_SPECIAL))
  497.       (void)fprintf(stderr, "em special: Linewidth set to %.1f dots\n", 
  498.         emwidth) ;
  499. #endif
  500.        } else {
  501.           sprintf(errbuf,"Unknown em: special width");
  502.           error(errbuf);
  503.        }
  504.     }
  505.         else if (strncmp(emp, "moveto", 6) == 0) {
  506. #ifdef DEBUG
  507.    if (dd(D_SPECIAL))
  508.       (void)fprintf(stderr, "em special: moveto %ld,%ld\n", hh, vv);
  509. #endif
  510.            emx = hh;
  511.            emy = vv;
  512.         }
  513.         else if (strncmp(emp, "lineto", 6) == 0) {
  514. #ifdef DEBUG
  515.    if (dd(D_SPECIAL))
  516.       (void)fprintf(stderr, "em special: lineto %ld,%ld\n", hh, vv);
  517. #endif
  518.        cmdout("np");
  519.        numout(emx);
  520.        numout(emy);
  521.        cmdout("a");
  522.        numout(hh);
  523.        numout(vv);
  524.        cmdout("li");
  525.        cmdout("st");
  526.            emx = hh;
  527.            emy = vv;
  528.         }
  529.     else if (strncmp(emp, "point", 5) == 0) {
  530.            if (empoints == NULL) {
  531.               if (( empoints = 
  532.                   (struct empt *)malloc(EMMAX * sizeof(struct empt)) )
  533.                   == (struct empt *)NULL)
  534.                    error("! can't allocate em: points space") ;
  535.               emused = TRUE;
  536.               emclear();
  537.            }
  538.        for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
  539.            empoint1 = (shalfword)atoi(emp);
  540.            empoint = emptput(empoint1,hh,vv);
  541. #ifdef DEBUG
  542.    if (dd(D_SPECIAL))
  543.       (void)fprintf(stderr, "em special: Point %d is %ld,%ld\n",
  544.         empoint->point, empoint->x, empoint->y) ;
  545. #endif
  546.     }
  547.     else if (strncmp(emp, "line", 4) == 0) {
  548.        for (emp = emp+4; *emp && isspace(*emp); emp++); /* skip blanks */
  549.            empoint1 = (shalfword)atoi(emp);
  550.        for (; *emp && isdigit(*emp); emp++); /* skip point 1 */
  551.        if ( *emp && strchr("hvp",*emp)!=0 )
  552.           emp++;  /* skip line cut */
  553.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  554.        if ( *emp && ispunct(*emp) )
  555.           emp++; /*  skip comma separator */
  556.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  557.            empoint2 = (shalfword)atoi(emp);
  558.        for (; *emp && isdigit(*emp); emp++); /* skip point 2 */
  559.        if ( *emp && strchr("hvp",*emp)!=0 )
  560.           emp++;  /* skip line cut */
  561.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  562.        if ( *emp && ispunct(*emp) )
  563.           emp++; /*  skip comma separator */
  564.        emwidth = -1.0;
  565.        emunit[0]='\0';
  566.        sscanf(emp, "%f%2s", &emwidth, emunit);
  567.        emwidth = emunits(emwidth,emunit);
  568. #ifdef DEBUG
  569.    if (dd(D_SPECIAL))
  570.       (void)fprintf(stderr, "em special: Line from point %d to point %d\n",
  571.         empoint1, empoint2) ;
  572. #endif
  573.        cmdout("np");
  574.        if (emwidth!=-1.0) {
  575. #ifdef DEBUG
  576.    if (dd(D_SPECIAL))
  577.    (void)fprintf(stderr,"em special: Linewidth temporarily set to %.1f dots\n", 
  578.         emwidth) ;
  579. #endif
  580.            strcpy(emstr,"currentlinewidth");
  581.            cmdout(emstr);
  582.             sprintf(emstr,"%.1f setlinewidth", emwidth);
  583.             cmdout(emstr);
  584.        }
  585.            empoint = emptget(empoint1);
  586.        numout(empoint->x);
  587.        numout(empoint->y);
  588.        cmdout("a");
  589.            empoint = emptget(empoint2);
  590.        numout(empoint->x);
  591.        numout(empoint->y);
  592.        cmdout("li");
  593.        cmdout("st");
  594.        if (emwidth!=-1.0) {
  595.            strcpy(emstr,"setlinewidth");
  596.            cmdout(emstr);
  597.        }
  598.     }
  599.     else if (strncmp(emp, "message", 7) == 0) {
  600.            (void)fprintf(stderr, "em message: %s\n", emp+7) ;
  601.     }
  602.     else {
  603.            sprintf(errbuf, 
  604.           "Unknown em: command (%s) in \\special will be ignored", p);
  605.            error(errbuf) ;
  606.     }
  607.     return;
  608.    }
  609. #endif /* EMTEX */
  610.  
  611.    if (strncmp(p, "ps:", 3)==0) {
  612.         hvpos() ;
  613.         psflush() ; /* now anything can happen. */
  614.         if (p[3]==':') {
  615.            if (strncmp(p+4, "[begin]", 7) == 0)
  616.               nlcmdout(&p[11]);
  617.            else if (strncmp(p+4, "[end]", 5) == 0)
  618.               nlcmdout(&p[9]);
  619.            else nlcmdout(&p[4]);
  620.         } else if (strncmp(p+3, " plotfile ", 10) == 0) {
  621.            char *sfp ;
  622.            p += 13;
  623.            for (sfp = p; *sfp && *sfp != ' '; sfp++) ;
  624.            *sfp = '\0';
  625.            figcopyfile (p, 0);
  626.         } else
  627.            nlcmdout(&p[3]);
  628.         return;
  629.    }
  630.    if (strncmp(p, "landscape", 9)==0 || strncmp(p, "header", 6)==0 || *p=='!')
  631.       return ; /* already handled in prescan */
  632. #ifdef TPIC
  633. /* ordered as in tpic 2.0 documentation for ease of cross-referencing */
  634.    if (strncmp(p, "pn ", 3) == 0) {setPenSize(p+2); return;}
  635.    if (strncmp(p, "pa ", 3) == 0) {addPath(p+2); return;}
  636.    if (strcmp(p, "fp") == 0) {flushPath(0); return;}
  637.    if (strcmp(p, "ip") == 0) {flushPath(1); return;} /* tpic 2.0 */
  638.    if (strncmp(p, "da ", 3) == 0) {flushDashed(p+2, 0); return;}
  639.    if (strncmp(p, "dt ", 3) == 0) {flushDashed(p+2, 1); return;}
  640.    if (strcmp(p, "sp") == 0) {flushSpline(p+2); return;} /* tpic 2.0 */
  641.    if (strncmp(p, "sp ", 3) == 0) {flushSpline(p+3); return;} /* tpic 2.0 */
  642.    if (strncmp(p, "ar ", 3) == 0) {arc(p+2, 0); return;} /* tpic 2.0 */
  643.    if (strncmp(p, "ia ", 3) == 0) {arc(p+2, 1); return;} /* tpic 2.0 */
  644.    if (strcmp(p, "sh") == 0) {shadeLast(p+2); return;} /* tpic 2.0 */
  645.    if (strncmp(p, "sh ", 3) == 0) {shadeLast(p+3); return;} /* tpic 2.0 */
  646.    if (strcmp(p, "wh") == 0) {whitenLast(); return;}
  647.    if (strcmp(p, "bk") == 0) {blackenLast(); return;}
  648.    if (strncmp(p, "tx ", 3) == 0) {SetShade(p+3); return;}
  649. #endif
  650.    if (*p == '"') {
  651.       hvpos();
  652.       cmdout("@beginspecial") ;
  653.       cmdout("@setspecial\n") ;
  654.       trytobreakout(p+1) ;
  655.       cmdout("\n@endspecial") ;
  656.       return ;
  657.    }
  658.  
  659. /* At last we get to the key/value conventions */
  660.    psfile[0] = '\0';
  661.    hvpos();
  662.    cmdout("@beginspecial");
  663.  
  664.    while( (p=GetKeyVal(p,&j)) != NULL )
  665.       switch (j) {
  666.  case -1: /* for compatability with old conventions, we allow a file name
  667.            * to be given without the 'psfile=' keyword */
  668.          if (!psfile[0] && access(KeyStr,4)==0) /* yes we can read it */
  669.              (void)strcpy(psfile,KeyStr) ;
  670.          else {
  671.            sprintf(errbuf, "Unknown keyword (%s) in \\special will be ignored",
  672.                               KeyStr) ;
  673.            error(errbuf) ;
  674.          }
  675.          break ;
  676.  case 0: /* psfile */
  677.          if (psfile[0]) {
  678.            sprintf(errbuf, "More than one \\special %s given; %s ignored", 
  679.                     j ? "system" : "psfile",  ValStr) ;
  680.            error(errbuf) ;
  681.          }
  682.          else (void)strcpy(psfile,ValStr) ;
  683.          break ;
  684.  case 1: case 2:
  685.          sprintf(errbuf, 
  686.             "Sorry, there's presently no \\special support for %s", KeyStr) ;
  687.          error(errbuf) ;
  688.          psfilewanted = 0 ;
  689.          break ;
  690.  default: /* most keywords are output as PostScript procedure calls */
  691.          if (KeyTab[j].Type == Integer)
  692.             numout(ValInt);
  693.          else if (KeyTab[j].Type == String)
  694.             for (q=ValStr; *q; q++)
  695.                scout(*q) ;
  696.          else if (KeyTab[j].Type == None) ;
  697.          else { /* Number or Dimension */
  698.             ValInt = (integer)(ValNum<0? ValNum-0.5 : ValNum+0.5) ;
  699.             if (ValInt-ValNum < 0.001 && ValInt-ValNum > -0.001)
  700.                 numout(ValInt) ;
  701.             else {
  702.                (void)sprintf(cmdbuf, "%f", ValNum) ;
  703.                cmdout(cmdbuf) ;
  704.             }
  705.          }
  706.       (void)sprintf(cmdbuf, "@%s", KeyStr);
  707.       cmdout(cmdbuf) ;
  708.       }
  709.  
  710.    cmdout("@setspecial");
  711.  
  712.    if(psfile[0]) {
  713.       systemtype = (psfile[0]=='`') ;
  714.       figcopyfile(psfile+systemtype, systemtype);
  715.    } else if (psfilewanted)
  716.       error("No \\special psfile was given; figure will be blank") ;
  717.  
  718.    cmdout("@endspecial");
  719. }
  720.